package RW;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import Excepciones.CiudadNoExisteException;
import Mundo.Caso;
import Mundo.Ciudad;
import Mundo.Viaje;

/**
 * Lee del archivo de datos
 * @author carlos
 *
 */
public class Lector 
{
	
	// ------------------------
    // CONSTANTES
	// ------------------------
	
	/**
	 * Ruta del archivo para cargar los datos de las ecuaciones a resolver.
	 */
	final static String RUTA_ARCHIVO = "./redt.in";
	
	/**
	 * Contiene los dias de la semana
	 */
	private static final String[] dias = {"Do","Lu","Ma","Mi","Ju","Vi","Sa"};
	
	public final static int MINUTOS_EN_UNA_SEMANA = 10080;
	
	// ------------------------
    // ATRIBUTOS
	// ------------------------
	
	/**
	 * Atributos para la entrada de datos.
	 */
	static File archivo;
	static FileReader reader;
	static BufferedReader lector;
	
	/**
	 * L�nea que est� leyendo actualmente
	 */
	static String linea;
	
	/**
	 * Caso actual que se esta resolviendo
	 */
	private static Caso caso;
	
	/**
	 * Arreglo con la ultima cadena dividida para leer
	 */
	private static String[] split;
	
	/**
	 * Arreglo con los tiempos de espera de cada ciudad
	 */
	private static Integer[] tiempoEspera;
	
	static int numCiudades, numRutas;
	
	/**
	 * 
	 */
	public static String[] rutasLeidas;

	
	// ------------------------
    // METODO CONSTRUCTOR
	// ------------------------
	
	public Lector()
	{
		archivo = new File (RUTA_ARCHIVO);
		try 
		{
			reader = new FileReader(archivo);
		} catch (FileNotFoundException e) 
		{
			System.out.println("No se encontr� el archivo con los datos de entrada.");
		}
		lector = new BufferedReader(reader);
	}
	

	
	
	// ------------------------
    // METODOS
	// ------------------------
	
	/**
	 * Lee la siguiente l�nea de la entrada de datos
	 * @throws IOException 
	 * @throws IOException 
	 */
	public void iniciar() throws IOException
	{	
		caso = new Caso();
		
		avanzarLinea();
		split = linea.split(" ");
		numCiudades = Integer.parseInt(split[0]);
		numRutas = Integer.parseInt(split[1]);
		tiempoEspera = new Integer[numCiudades+1];
		rutasLeidas = new String[numRutas];
	}
	
	public void leerCiudades() throws IOException 
	{	
		numCiudades = Integer.parseInt(split[0]);
		numRutas = Integer.parseInt(split[1]);
		
		for (int i = 0; i < numCiudades; i++) 
		{
			avanzarLinea();	
			split = linea.split(" ");
			Ciudad c = new Ciudad(split[0], i+1,Integer.parseInt(split[1]));
			caso.agregarCiudad(c);
			tiempoEspera[i+1] = Integer.parseInt(split[1]);
		}
	}


	public void leerRutas() throws IOException 
	{		
		for (int i = 0; i < numRutas; i++) 
		{
			avanzarLinea(); // Lee la linea: Ruta #. (no hay que hacer nada)
			avanzarLinea(); // Lee la linea: nds
			String dia = dias[Integer.parseInt(linea)];
			
			avanzarLinea(); // Lee la linea: h m f v
			split = linea.split(" ");
			int[]hora = new int[2];
			hora[0] = Integer.parseInt(split[0]); 
			hora[1] = Integer.parseInt(split[1]);
			int frecuencia = Integer.parseInt(split[2]);
			int veces = Integer.parseInt(split[3]);
			
			int vecesPorFrecuencia = veces*frecuencia;
			if(vecesPorFrecuencia >= MINUTOS_EN_UNA_SEMANA)
				{veces = MINUTOS_EN_UNA_SEMANA/frecuencia;Escritor.escribir("veces "+veces);}
			
			int[]originalHora= new int[2];
			originalHora[0] = hora[0]; originalHora[1] = hora[1];
			String originalDia = new String(dia);

			
			avanzarLinea(); // Lee la ruta hasta q termina en 0
			rutasLeidas[i] = linea;
			split = linea.split(" ");
			
			for (int a = 0; a < veces; a++) 
			{
				originalHora = hora.clone();
				originalDia = new String(dia);
				
				// agrega los viajes sacados de la ruta
				int j=0;
				while(!split[j+1].equals("0"))
				{			
					String ciudadOrigen = split[j];
					String ciudadDestino = split[j+2];
					int demora = Integer.parseInt(split[j+1]);
					int tiempoEsperaEnCiudad= tiempoEspera[Integer.parseInt(ciudadOrigen)];
										
					if(j!=0)
					{
						sumarMinutos(dia, hora, tiempoEsperaEnCiudad);
					}
					caso.agregarViaje(ciudadOrigen, ciudadDestino,new String(dia),hora.clone(),demora);
					sumarMinutos(dia,hora,demora); //Cambia el dia y la hora al sumar los minutos de demora
					
					j+=2;
				}
				
				hora = originalHora.clone();
				dia = new String(originalDia);
				
				sumarMinutos(dia, hora, frecuencia);
			}			
		}
		
		Escritor.escribir("Viajes creados:");
		Collection ciudades = caso.getCiudades().values(); int contador=0;
		for (Iterator iterator = ciudades.iterator(); iterator
				.hasNext();) {
			Ciudad c = (Ciudad) iterator.next();
			
			ArrayList<Viaje> viajes = c.getViajes();
			for (int x = 0; x < viajes.size(); x++) {
						
						contador++;Escritor.escribir("Viajes de "+c.getNombre()+" a "+viajes.get(x).getCiudadDestino().getNombre()+" (de "+c.getId()+" a "+viajes.get(x).getCiudadDestino().getId()+"): "+(x+1)+"/"+viajes.size()+": Dia "+viajes.get(x).getDia()+". Hora "+viajes.get(x).getHora()[0]+":"+viajes.get(x).getHora()[1]);
					}
		} Escritor.escribir("Total Viajes: "+contador);
	}

	public void leerYResolverCasos() throws IOException 
	{
		avanzarLinea();
		int i = 1;
		while(!linea.equals("0 0 0 0 0"))
		{
			split = linea.split(" ");
			String dia = dias[Integer.parseInt(split[0])];		
			
			int numCiudadOrigen = Integer.parseInt(split[1]);
			int numCiudadDestino = Integer.parseInt(split[2]);
			int[] hora = new int[2];
			hora[0] = Integer.parseInt(split[3]);
			hora[1] = Integer.parseInt(split[4]);
			
			caso.setDia(dia);
			caso.setHora(hora);
			caso.setNumCiudadInicial(numCiudadOrigen+"");
			caso.setNumCiudadDestino(numCiudadDestino+"");
			
			//Resolver caso!!!
			
			Escritor.escribir("Caso "+i+":");
			Escritor.escribirLineaCaso(caso.getNombreCiudadInicial(),caso.getNombreCiudadDestino(),
					dia, hora);
			Escritor.escribirLinea10Guiones();
			
			try 
			{
				String respuesta = caso.buscarCaminoOptimo();
				
				if(respuesta.equals(""))
					respuesta = "No solucion\ninfinito";
				Escritor.escribir(respuesta);
			} catch (CiudadNoExisteException e) 
			{
				Escritor.escribir("Error: "+e.getMessage());
			}
			Escritor.escribirLinea20Guiones();
			i++;
			avanzarLinea();
		}
	}
	
	
	//COmplejidad de o(v) donde v es la cantidad de viajes que hay en una ciduad en especial. para el caso,
	// la ciduad que se nos da para la busqueda.
	public boolean hayCamino(Ciudad a, Ciudad b, String diaa,String diab,int[] horaa, int[] horab)
	{
		boolean r=false;
		
		ArrayList<Viaje> ar=a.getViajes();
		for(int i=0;i<ar.size()&&!r;i++)
		{
			Viaje temporal=ar.get(i);
			String dia=temporal.getDia();
			int[] hora=temporal.getHora();
			int[] llegada=temporal.getHora();
			llegada[1]+=temporal.getDemora();
			Ciudad ciudad=temporal.getCiudadDestino();
			if(dia.equals(diaa)&&hora==horaa&&ciudad==b&&horab==llegada)
			{
				r=true;
			}
		}
		
		return r;
	}

	/**
	 * Cambia el Dia y la hora que llegan por parametro, al sumar una cantidad de minutos
	 * @param dia Dia de la semana	
	 * @param hora Arreglo que contiene las horas y minutos en hora[0] y hora[1] respectivamente
	 * @param minutosASumar
	 */
	private void sumarMinutos(String dia, int[] hora, int minutosASumar) 
	{
		int tempMinutos = hora[1] + minutosASumar;
		if(tempMinutos >= 60)
		{
			hora[1] = tempMinutos % 60;
			int tempHoras = hora[0] + (tempMinutos)/60;
			if(tempHoras >= 24)
			{
				int tempDia = tempHoras/24;
				hora[0] = tempHoras % 24;
				dia = sumarDias(dia,tempDia);
			}
			else
			{
				hora[0] = tempHoras;
			}
		}
		else
		{
			hora[1] = tempMinutos;
		}
	}


	/**
	 * Cambia el dia de la semana despues de sumar una cantidad de dias
	 * @param dia
	 * @param diasASumar. Entre 1 y ...
	 * @return
	 */
	public String sumarDias(String dia,int diasASumar) 
	{		
			for (int i = 0; !dias[i].equals(dia); i++) 
			{
				if (dias[i].equals(dia))
				{
					return dias[(i+diasASumar)%7];
				}
			}
			return null;
	}
	
	public void avanzarLinea() throws IOException
	{
		linea = lector.readLine();
	}
	
	public static int getNumCiudades()
	{
		return numCiudades;
	}

	
}
